package com.rookie.rabbit.modular.config;


import com.rabbitmq.client.Channel;
import com.rookie.rabbit.modular.entity.DefaultQueueMessage;
import com.rookie.rabbit.modular.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @author rookie
 * @date 2021/6/16
 */
@Slf4j
@Aspect
@Component
public class RabbitAop {

    @Value("${spring.rabbitmq.consumerId:-1}")
    private String consumerId;

    @Pointcut("@annotation(org.springframework.amqp.rabbit.annotation.RabbitListener)")
    public void pointCut() {
    }

    @Around(value = "pointCut()")
    public Object after(ProceedingJoinPoint pjp) throws Throwable {
        boolean process = pointConsumerMessage(pjp);
        if (process) {
            return pjp.proceed();
        } else {
            return null;
        }
    }

    /**
     * 指定消费者消费判断
     *
     * @param pjp pjp
     * @throws IOException 异常
     */
    private boolean pointConsumerMessage(ProceedingJoinPoint pjp) throws IOException {
        Channel channel = null;
        int step = 0;
        long tag = 0;
        Object[] args = pjp.getArgs();
        if (args.length > 0 && args[0] != null) {
            String message = null;
            if (args[0] instanceof String) {
                message = (String) args[0];
            } else {
                return true;
            }

            MethodSignature signature = (MethodSignature) pjp.getSignature();
            Method method = signature.getMethod();

            Annotation[][] annotations = method.getParameterAnnotations();

//            获取需要回滚的参数
            for (int i = 0; i < annotations.length; i++) {
                if (step == 2) {
                    break;
                }
                try {
                    Object arg = args[i];
                    if (arg instanceof Channel) {
                        channel = (Channel) arg;
                        step++;
                        continue;
                    }
                } catch (Exception e) {
                    return true;
                }
                if (annotations[i].length < 1) {
                    continue;
                }
                for (Annotation paramAnnotation : annotations[i]) {
                    if (paramAnnotation.annotationType().equals(Header.class)) {
                        tag = (long) args[i];
                        step++;
                    }
                }
            }

//           缺少回滚参数直接结束
            if (step != 2 || channel == null) {
                return true;
            }
            DefaultQueueMessage defaultQueueMessage = JsonUtils.getBean(message, DefaultQueueMessage.class);
            //                    如果发送的消息中存在指定消费者配置
            if (defaultQueueMessage != null && defaultQueueMessage.getConsumerId() != null) {
                if (!defaultQueueMessage.getConsumerId().equals(consumerId)) {
//                    非指定消费者则直接拒绝消息
                    channel.basicReject(tag, true);
                    return false;
                }
            }
        }

        return true;
    }
}
